/* 
 * Rug.Cmd part of Rugland Console Framework
 * 
 * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
 * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
 * 
 * Copyright (C) 2008 Phill Tew. All rights reserved.
 * 
 */

using System;
using System.Collections.Generic;
using System.Text;
using Rug.Cmd.Gui;
using System.IO;
using Rug.Cmd.Colors;

namespace Rug.Cmd
{
	/// <summary>
	/// Parse command line arguments
	/// </summary>
	public class ArgumentParser
	{
		#region Private Members 
		
		#region Arguments and state

		// Lookup for all arguments
		private Dictionary<ArgumentKey, IArgumentValue> m_Switches = new Dictionary<ArgumentKey, IArgumentValue>();
		// The first argument 
		private IArgumentValue m_FirstArgument = null;
		// The default / fallback argument 
		private StringListArgument m_DefaultArgument = null;

		// is this / the last execution of the parse in help mode 
		private bool m_HelpMode = false;
		// has this application got documentation
		private bool m_HasApplicationDocument;

		#endregion

		#region Application Info Members

		private string m_AppName;        
		private string m_Description;        
		private string m_AboutTitleText = null;
		private string m_AboutText = null;
		private string m_AboutTextLong = null;
		private string m_CreditsText = null;
		private string m_UsageText = null;
		private string m_LegalText = null;

		#endregion
		
		#endregion

		#region Properties

		/// <summary>
		/// Gets the name of the appliaction
		/// </summary>
		public string Name { get { return m_AppName; } }
		
		/// <summary>
		/// Gets or sets the title for the about text
		/// </summary>
		public string AboutTitleText { get { return m_AboutTitleText; } set { m_AboutTitleText = value; } }

		/// <summary>
		/// Gets or sets the about text
		/// </summary>
		public string AboutText { get { return m_AboutText; } set { m_AboutText = value; } }

		/// <summary>
		/// Gets or sets the long about text
		/// </summary>
		public string AboutTextLong { get { return m_AboutTextLong; } set { m_AboutTextLong = value; } }

		/// <summary>
		/// Gets or sets the credits text
		/// </summary>
		public string CreditsText { get { return m_CreditsText; } set { m_CreditsText = value; } }

		/// <summary>
		/// Gets or sets the usage text
		/// </summary>
		public string UsageText { get { return m_UsageText; } set { m_UsageText = value; } }

		/// <summary>
		/// Gets or sets the legal text
		/// </summary>
		public string LegalText { get { return m_LegalText; } set { m_LegalText = value; } }

		/// <summary>
		/// Gets or sets the IArgumentValue to use for the first arguemnt 
		/// </summary>
		public IArgumentValue FirstArgument { get { return m_FirstArgument; } set { m_FirstArgument = value; } }
		
		/// <summary>
		/// Gets or sets the StringListArgument to use as the default argument
		/// </summary>
		public StringListArgument DefaultArgument { get { return m_DefaultArgument; } set { m_DefaultArgument = value; } }

		/// <summary>
		/// Has this application got any about text at all 
		/// </summary>
		public bool HasApplicationAbout
		{
			get
			{
				return
					m_AboutTitleText != null ||
					m_AboutText != null ||
					m_AboutTextLong != null ||
					m_CreditsText != null ||
					m_UsageText != null ||
					m_LegalText != null;
			}
		}

		/// <summary>
		/// Gets or sets HasApplicationDocument flag. If true the '/?D' argument will be visible in the arguments list
		/// </summary>
		public bool HasApplicationDocument
		{
			get { return m_HasApplicationDocument; }
			set { m_HasApplicationDocument = value; }
		}

		/// <summary>
		/// Creates a new ArgumentParser
		/// </summary>
		/// <param name="appName">usually the name of the .exe file (without the extention), e.g. 'rpx.exe' = 'RPX'</param>
		/// <param name="description">description text</param>
		public ArgumentParser(string appName, string description)
		{
			this.m_AppName = appName;
			this.m_Description = description; 
		}

		/// <summary>
		/// True if the /? switch was defined 
		/// </summary>
		public bool HelpMode
		{
			get { return m_HelpMode; }
		}

		#endregion
		
		#region Argument Collection 

		#region Argument Keys
		
		/// <summary>
		/// All the ArgumentKey(s)
		/// </summary>
		public IEnumerable<ArgumentKey> Keys { get { return (IEnumerable<ArgumentKey>)m_Switches.Keys; } } 

		/// <summary>
		/// Gets IArgumentValue for a string e.g. '/O' or '/Option'
		/// </summary>
		/// <param name="key">string key to match e.g. '/O' or '/Option' </param>
		/// <returns>IArgumentValue that has that key or null if none was found</returns>
		public IArgumentValue this[string key]
		{
			get 
			{
				foreach (ArgumentKey k in m_Switches.Keys)
				{
					// match against the ArguemntKey 
					if (k.Equals(key))
						return m_Switches[k];
				}

				return null; 
			}			
		}
	
		/// <summary>
		/// Does this ArgumentParser contain string key e.g. '/O' or '/Option'
		/// </summary>
		/// <param name="key">string key to match e.g. '/O' or '/Option'</param>
		/// <returns>true if the key was found</returns>
		public bool ContainsKey(string key)
		{
			foreach (ArgumentKey k in m_Switches.Keys)
			{
				if (k.Equals(key))
					return true;
			}

			return false;
		}

		/// <summary>
		/// Gets the IArgumentValue and ArgumentKey for a given string key 
		/// </summary>
		/// <param name="keyIn">string key to match e.g. '/O' or '/Option'</param>
		/// <param name="outKey">the ArgumentKey acociated with the resulting IArgumentValue</param>
		/// <returns>IArgumentValue that has that key or null if none was found</returns>
		public IArgumentValue GetForKey(string keyIn, out ArgumentKey outKey)
		{
			foreach (ArgumentKey k in m_Switches.Keys)
			{
				if (k.Equals(keyIn))
				{
					outKey = k;
					return m_Switches[k];
				}
			}

			outKey = null;

			return null;
		}

		#endregion

		#region Contains Symbol

		/// <summary>
		/// Does this parser contain a symbol (Searches on the symbols only)
		/// </summary>
		/// <param name="symbol">symbol</param>
		/// <returns>true if the symbol was found</returns>
		public bool ContainsSymbol(string symbol)
		{
			foreach (ArgumentKey k in m_Switches.Keys)
			{
				if (k.Symbol.Equals(symbol, StringComparison.InvariantCultureIgnoreCase))
					return true;
			}

			return false;
		}

		#endregion

		#region Lookup Argument By Name

		/// <summary>
		/// Does this parser contain a name (Searches on the name only)
		/// </summary>
		/// <param name="name">name</param>
		/// <returns>true if the name was found</returns>
		public bool ContainsName(string name)
		{
			foreach (ArgumentKey k in m_Switches.Keys)
			{
				if (k.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
					return true;
			}

			return false;
		}

		/// <summary>
		/// Get the argument for a name 
		/// </summary>
		/// <param name="name">name</param>
		/// <returns>the argument if the name was found or null if it was not</returns>
		public IArgumentValue GetForName(string name)
		{
			foreach (ArgumentKey k in m_Switches.Keys)
			{
				if (k.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
					return m_Switches[k];
			}

			return null;
		}

		#endregion

		#region Add Argument

		/// <summary>
		/// Adds a IArgumentValue to the parsers Switches collection.
		/// </summary>
		/// <param name="prefix">prefix for the switch. typically '/' </param>
		/// <param name="key">the key for the switch</param>
		/// <param name="value">the argument to add</param>
		public void Add(string prefix, string key, IArgumentValue value)
		{
			if (!ContainsName(key))
			{
				for (int i = 1, e = key.Length; i < e; i++)
				{
					if (!ContainsSymbol(key.Substring(0, i)))
					{
						m_Switches.Add(new ArgumentKey(prefix, key, key.Substring(0, i)), value);
						return;
					}
				}

				throw new Exception(string.Format(Strings.ArgumentParser_Add_CannotMatchSymbolForKey, key)); 
			}
			else
				throw new Exception(string.Format(Strings.ArgumentParser_Add_AllreadyContainsKey, key)); 
		}


		/// <summary>
		/// Adds a IArgumentValue to the parsers Switches collection.
		/// </summary>
		/// <param name="prefix">prefix for the switch. typically '/' </param>
		/// <param name="symbol">the explicit symbol to use</param>
		/// <param name="key">the key for the switch</param>
		/// <param name="value">the argument to add</param>
		public void Add(string prefix, string symbol, string key, IArgumentValue value)
		{
			if (!ContainsSymbol(symbol))
			{
				m_Switches.Add(new ArgumentKey(prefix, key, symbol), value);
				return;
			}

			throw new Exception(string.Format(Strings.ArgumentParser_Add_SymbolInUse, symbol));
		}

		#endregion 

		#endregion

		#region Parse, Reset and Check Definition

		#region Reset

		/// <summary>
		/// Resets the parser and all its arguments 
		/// </summary>
		public void Reset()
		{
			m_HelpMode = false; 

			if (m_FirstArgument != null)
				m_FirstArgument.Reset();

			if (m_DefaultArgument != null)
				m_DefaultArgument.Reset();

			foreach (IArgumentValue value in m_Switches.Values)
			{
				value.Reset();
			}
		}

		#endregion

		#region WasDefined
		
		/// <summary>
		/// Was the arguemnt with the name get defined last time the parser was run? 
		/// </summary>
		/// <param name="name">the name of the argument</param>
		/// <returns>true if the argument was defined</returns>
		public bool WasDefined(string name)
		{
			IArgumentValue val = GetForName(name);

			if (val != null)
				return val.Defined;

			return false;
		}

		#endregion

		#region Parse

		/// <summary>
		/// Parse argument from args array
		/// </summary>
		/// <param name="args">the command line arguments</param>
		public void Parse(string[] args)
		{
			ConsoleColorState state = RC.ColorState;

			try
			{
				if (args.Length > 0)
				{
					int index = 0;

					StringListArgument current = null;

					if (args[0] == "/?")
					{
						if (args.Length == 1)
						{
							WriteLongArgumentsUsage();
						}
						else
						{ 
							WriteShortArgumentsUsage();
						}

						m_HelpMode = true;
						index++;
					}
					else if (args[0] == "/??")
					{
						WriteApplicationAboutToConsole(true);

						m_HelpMode = true;
						index++;
					}
					else if (args[0].Equals("/?D", StringComparison.CurrentCultureIgnoreCase))
					{
						string path;

						if (args.Length > 1)
							path = args[1];
						else
							path = Path.Combine(Environment.CurrentDirectory, m_AppName + " Documentation.txt");

						WriteApplicationDocumentationToPath(path);

						m_HelpMode = true;

						return;
					}
					else if (m_FirstArgument != null)
					{
						m_FirstArgument.SetValue(args[0]);
						m_FirstArgument.Defined = true;

						if (m_FirstArgument is StringListArgument)
						{
							current = m_FirstArgument as StringListArgument;
						}

						index++;
					}

					for (int i = index, ie = args.Length; i < ie; i++)
					{
						string key = args[i];
						string lookupKey = key;

						if (key.StartsWith("-") || key.StartsWith("+"))
							lookupKey = ConsoleChars.GetMathsChar(ConsoleMathsChars.PlusMinus) + key.Substring(1);

						ArgumentKey actualKey = null;
						IArgumentValue v = null;

						if (this.ContainsKey(key))
						{
							v = GetForKey(key, out actualKey);
						}
						else if (!lookupKey.Equals(key) && this.ContainsKey(lookupKey))
						{
							v = GetForKey(lookupKey, out actualKey);
						}

						if (actualKey != null && v != null)
						{
							if (m_HelpMode)
							{
								WriteIndividualHelpToConsole(actualKey);
							}
							else
							{
								v.Defined = true;

								if (v.Parse(this, key, args, ref i))
								{
									current = v as StringListArgument;
								}
								else
								{ 
									current = null;
								}
							}
						}
						else if (current != null && !m_HelpMode)
						{
							current.SetValue(key);
						}
						else if (m_DefaultArgument != null && !m_HelpMode)
						{
							m_DefaultArgument.SetValue(key);
						}
						else
						{ 
							throw new Exception(string.Format(Strings.ArgumentParser_InvalidSwitch, key));
						}
					}
				}
			}
			finally
			{
				RC.ColorState = state;
			}
		}

		#endregion

		#endregion 

		#region Argument and Doc Write and String Helpers

		#region Get Short Arguments Usage

		/// <summary>
		/// Get the short arguments usage in the form of a string
		/// </summary>
		/// <returns>the short help string</returns>
		public string GetShortArgumentsUsage()
		{
			StringBuilder args = new StringBuilder();
			StringBuilder sb = new StringBuilder();

			args.AppendLine(m_Description);
			args.AppendLine("");
			args.Append(m_AppName.ToUpper() + " ");

			if (m_FirstArgument != null)
				args.Append("<" + m_FirstArgument.ArgumentString().Trim() + "> ");

			if (m_DefaultArgument != null)
				args.Append("<" + m_DefaultArgument.ArgumentString().Trim() + "> ");

			foreach (ArgumentKey k in m_Switches.Keys)
			{
				IArgumentValue v = m_Switches[k];
				
				args.Append("[" + k.Prefix + k.Symbol.ToUpper() + v.ArgumentString() + "] ");
			}

			if (HasApplicationAbout)
			{
				args.Append("/?? ");
			}

			if (HasApplicationDocument)
			{
				args.Append("/?D <" + Strings.ArgumentParser_Documentation_NameForPath + "> ");
			}

			args.AppendLine("");
			args.AppendLine("");

			return args.ToString();
		}
		
		#endregion

		#region Write Short Arguments Usage

		/// <summary>
		/// Writes the short arguments usage to the console 
		/// </summary>
		public void WriteShortArgumentsUsage()
		{
			ConsoleColorState state = RC.ColorState;

			RC.ForegroundThemeColor = ConsoleThemeColor.TitleText;

			RC.WriteLine(ConsoleVerbosity.Silent, m_Description);
			RC.WriteLine(ConsoleVerbosity.Silent);

			int prefixLength = m_AppName.Length + 1; 
			int length = prefixLength; 
			RC.Write(ConsoleVerbosity.Silent, m_AppName.ToUpper() + " ");
			

			if (m_FirstArgument != null)
			{
				string argString = "<" + m_FirstArgument.ArgumentString().Trim() + "> ";

				length += argString.Length + argString.Length;

				if (length > RC.BufferWidth)
				{
					length = prefixLength;
					RC.WriteLine(); 
					RC.Write(new string(' ', prefixLength)); 
				}

				RC.Write(ConsoleVerbosity.Silent, ConsoleThemeColor.SubText2, argString);
			}

			if (m_DefaultArgument != null)
			{
				string argString = "<" + m_DefaultArgument.ArgumentString().Trim() + "> ";

				length += argString.Length;

				if (length > RC.BufferWidth)
				{
					length = prefixLength + argString.Length;
					RC.WriteLine();
					RC.Write(new string(' ', prefixLength));
				}

				RC.Write(ConsoleVerbosity.Silent, ConsoleThemeColor.SubText3, argString);
			}

			foreach (ArgumentKey k in m_Switches.Keys)
			{
				IArgumentValue v = m_Switches[k];

				int argLength = (k.Prefix.Length + k.Symbol.Length + v.ArgumentString().Length + 3);
				length += argLength;

				if (length > RC.BufferWidth)
				{
					length = prefixLength + argLength;
					RC.WriteLine();
					RC.Write(new string(' ', prefixLength));
				}

				RC.Write(ConsoleVerbosity.Silent, ConsoleThemeColor.SubText, "[");
				RC.Write(ConsoleVerbosity.Silent, ConsoleThemeColor.TitleText, k.Prefix + k.Symbol.ToUpper());
				RC.Write(ConsoleVerbosity.Silent, ConsoleThemeColor.Text, v.ArgumentString());
				RC.Write(ConsoleVerbosity.Silent, ConsoleThemeColor.SubText, "] ");
			}

			if (HasApplicationAbout)
			{
				int argLength = 4;
				length += argLength;

				if (length > RC.BufferWidth)
				{
					length = prefixLength + argLength;
					RC.WriteLine();
					RC.Write(new string(' ', prefixLength));
				}

				RC.Write(ConsoleVerbosity.Silent, ConsoleThemeColor.WarningColor2, "/?? ");
			}

			if (HasApplicationDocument)
			{
				int argLength = 11;
				length += argLength;

				if (length > RC.BufferWidth)
				{
					length = prefixLength + argLength;
					RC.WriteLine();
					RC.Write(new string(' ', prefixLength));
				}

				RC.Write(ConsoleVerbosity.Silent, ConsoleThemeColor.WarningColor2, "/?D <path> ");
			}

			RC.ColorState = state;

			RC.WriteLine(ConsoleVerbosity.Silent);
			RC.WriteLine(ConsoleVerbosity.Silent);
		}

		#endregion

		#region Write Long Arguments Usage

		/// <summary>
		/// Write the full arguemnts usage help to the console
		/// </summary>
		public void WriteLongArgumentsUsage()
		{
			ConsoleColorState state = RC.ColorState;

			WriteShortArgumentsUsage(); 

			if (m_FirstArgument != null)
			{
				if (Helper.IsNotNullOrEmpty(m_FirstArgument.Help))
				{
					RC.WriteLine(ConsoleVerbosity.Silent, ConsoleThemeColor.SubText2, "  <" + m_FirstArgument.ArgumentString().Trim() + ">");

					RC.WriteWrapped(ConsoleThemeColor.Text1, m_FirstArgument.Help, 4, 4);
					RC.WriteLine(ConsoleVerbosity.Silent, "");
				}
			}

			if (m_DefaultArgument != null)
			{
				if (Helper.IsNotNullOrEmpty(m_DefaultArgument.Help))
				{
					RC.WriteLine(ConsoleVerbosity.Silent, ConsoleThemeColor.SubText3, "  <" + m_DefaultArgument.ArgumentString().Trim() + ">");
					RC.WriteWrapped(ConsoleThemeColor.Text1, m_DefaultArgument.Help, 4, 2);
					RC.WriteLine(ConsoleVerbosity.Silent, "");
				}
			}

			foreach (ArgumentKey k in m_Switches.Keys)
			{
				IArgumentValue v = m_Switches[k];

				string keyString = k.Prefix + k.Symbol.ToUpper();

				RC.Write(ConsoleVerbosity.Silent, ConsoleThemeColor.TitleText, "  " + keyString);

				if (k.Name.ToUpper().StartsWith(k.Symbol.ToUpper()))
					RC.Write(ConsoleVerbosity.Silent, ConsoleThemeColor.Text, k.Name.Substring(k.Symbol.Length).PadRight(18 - keyString.Length));
				else
					RC.Write(ConsoleVerbosity.Silent, ConsoleThemeColor.Text, (" (" + k.Name + ")").PadRight(18 - keyString.Length));

				RC.WriteLine(ConsoleVerbosity.Silent, ConsoleThemeColor.Text1, " " + v.ShortHelp);
			}

			if (HasApplicationAbout)
			{
				RC.Write(ConsoleVerbosity.Silent, ConsoleThemeColor.WarningColor2, "  " + "/?? ".PadRight(18));
				RC.WriteLine(ConsoleVerbosity.Silent, ConsoleThemeColor.Text1, " " + Strings.ArgumentParser_AboutScreen_Title);
			}

			if (HasApplicationDocument)
			{
				RC.Write(ConsoleVerbosity.Silent, ConsoleThemeColor.WarningColor2, "  " + "/?D ".PadRight(18));
				RC.WriteLine(ConsoleVerbosity.Silent, ConsoleThemeColor.Text1, " " + Strings.ArgumentParser_DocumentGenerator_Title);
			}

			RC.ColorState = state;
		}

		#endregion

		#region Get Long Arguments Usage

		/// <summary>
		/// Get the full arguments usage help string
		/// </summary>
		/// <returns>the full help string</returns>
		public string GetLongArgumentsUsage()
		{
			StringBuilder sb = new StringBuilder();

			foreach (ArgumentKey k in m_Switches.Keys)
			{
				IArgumentValue v = m_Switches[k];

				string keyString = k.Symbol.ToUpper();

				if (k.Name.ToUpper().StartsWith(k.Symbol.ToUpper()))
					keyString += k.Name.Substring(k.Symbol.Length);
				else
					keyString += " (" + k.Name + ")";

				sb.AppendLine("  " + k.Prefix + keyString.PadRight(15) + " " + v.ShortHelp); 
			}

			if (HasApplicationAbout)
			{
				sb.AppendLine("  " + "/??".PadRight(15) + " " + Strings.ArgumentParser_AboutScreen_Title);
			}

			if (HasApplicationDocument)
			{
				sb.AppendLine("  " + "/?D".PadRight(15) + " " + Strings.ArgumentParser_DocumentGenerator_Title);
			}

			return GetShortArgumentsUsage() + sb.ToString();
		}

		#endregion		

		#region GetIndividualHelpString

		/// <summary>
		/// Get the individual help stirng for an argument
		/// </summary>
		/// <param name="k">the key for the argument</param>
		/// <returns>the help string</returns>
		public string GetIndividualHelpString(ArgumentKey k)
		{
			StringBuilder args = new StringBuilder();
			IArgumentValue v = m_Switches[k];

			args.Append("[" + k.Prefix + k.Symbol.ToUpper() + v.ArgumentString() + "] ");

			string keyString = k.Symbol.ToUpper();

			if (k.Name.ToUpper().StartsWith(k.Symbol.ToUpper()))
				keyString += k.Name.Substring(k.Symbol.Length);
			else
				keyString += " (" + k.Name + ")";

			args.AppendLine("  " + k.Prefix + keyString);

			args.AppendLine("  " + v.ShortHelp);
			args.AppendLine();

			if (Helper.IsNotNullOrEmpty(v.Help))
			{
				args.AppendLine(ConsoleFormatter.StripFormat(v.Help));
				args.AppendLine();
			}

			return args.ToString();
		}

		#endregion

		#region WriteIndividualHelpToConsole

		/// <summary>
		/// Write the individual help for an argument to the console
		/// </summary>
		/// <param name="k">the key for the argument</param>
		/// <param name="colourise">true if it should be colourised</param>
		public void WriteIndividualHelpToConsole(ArgumentKey k)
		{
			ConsoleColorState state = RC.ColorState;

			IArgumentValue v = m_Switches[k];

			RC.Write(ConsoleVerbosity.Silent, ConsoleThemeColor.SubText, new string('-', RC.BufferWidth) + "[");
			RC.Write(ConsoleVerbosity.Silent, ConsoleThemeColor.TitleText, k.Prefix + k.Symbol.ToUpper());
			RC.Write(ConsoleVerbosity.Silent, ConsoleThemeColor.Text, v.ArgumentString());
			RC.Write(ConsoleVerbosity.Silent, ConsoleThemeColor.SubText, "] ");
			RC.Write(ConsoleVerbosity.Silent, ConsoleThemeColor.TitleText, "  " + k.Prefix + k.Symbol.ToUpper());
			
			if (k.Name.ToUpper().StartsWith(k.Symbol.ToUpper()))
				RC.WriteLine(ConsoleVerbosity.Silent, ConsoleThemeColor.Text, k.Name.Substring(k.Symbol.Length).PadRight(15 - k.Symbol.Length));
			else
				RC.WriteLine(ConsoleVerbosity.Silent, ConsoleThemeColor.Text, (" (" + k.Name + ")").PadRight(15 - k.Symbol.Length));

			RC.WriteLine(ConsoleVerbosity.Silent, ConsoleThemeColor.Text1, "  " + v.ShortHelp);
			RC.WriteLine(ConsoleVerbosity.Silent, ConsoleThemeColor.TitleText, "");
			
			if (Helper.IsNotNullOrEmpty(v.Help))
			{
				RC.WriteInterpreted(ConsoleThemeColor.TitleText, v.Help, 2, 2);
				RC.WriteLine(ConsoleVerbosity.Silent, "");
			}

			RC.ColorState = state;
		}


		#endregion

		#region WriteApplicationAboutToConsole

		/// <summary>
		/// Write the application about to the console
		/// </summary>
		/// <param name="colourise">true if it should be colourised</param>
		private void WriteApplicationAboutToConsole(bool colourise)
		{
			if (m_AboutTitleText != null)
			{
				CmdHelper.WriteSimpleBanner(m_AboutTitleText, ' ', RC.Theme[ConsoleThemeColor.AppBackground], RC.Theme[ConsoleThemeColor.TitleText]);
				RC.WriteLine(ConsoleVerbosity.Silent); 
			}

			if (m_AboutText != null)
			{
				RC.WriteInterpreted(ConsoleThemeColor.TitleText, m_AboutText, 3, 3);
				RC.WriteLine(ConsoleVerbosity.Silent);
				RC.WriteLine(ConsoleVerbosity.Silent);
			}

			if (m_AboutTextLong != null)
			{
				RC.WriteInterpreted(ConsoleThemeColor.Text, m_AboutTextLong, 3, 3);
				RC.WriteLine(ConsoleVerbosity.Silent);
				RC.WriteLine(ConsoleVerbosity.Silent);
			}

			if (m_CreditsText != null)
			{
				RC.WriteInterpreted(ConsoleThemeColor.Text, m_CreditsText, 3, 3);
				RC.WriteLine(ConsoleVerbosity.Silent);
				RC.WriteLine(ConsoleVerbosity.Silent);
			}

			if (m_LegalText != null)
			{
				RC.WriteInterpreted(ConsoleThemeColor.SubText2, m_LegalText, 3, 3);
				RC.WriteLine(ConsoleVerbosity.Silent);
				RC.WriteLine(ConsoleVerbosity.Silent);
			}            

			if (m_UsageText != null)
			{
				RC.WriteLine(ConsoleVerbosity.Silent, ConsoleThemeColor.TitleText, string.Format(" {0}:", Strings.ArgumentParser_AboutScreen_Usage));
				RC.WriteInterpreted(ConsoleThemeColor.Text1, m_UsageText, 3, 3);
				RC.WriteLine(ConsoleVerbosity.Silent); 
			}
		}

		#endregion

		#region WriteApplicationDocumentationToPath

		/// <summary>
		/// Write the application documentation to a file path
		/// </summary>
		/// <param name="path">path of the file to write to</param>
		public void WriteApplicationDocumentationToPath(string path)
		{
			StringBuilder finalString = new StringBuilder(); 

			if (m_AboutTitleText != null)
			{
				finalString.AppendLine(ConsoleFormatter.StripFormat(m_AboutTitleText));
				finalString.AppendLine(); 
			}

			if (m_CreditsText != null)
			{
				finalString.AppendLine(ConsoleFormatter.StripFormat(m_CreditsText));
				finalString.AppendLine();
			}

			if (m_AboutText != null)
			{
				finalString.AppendLine(ConsoleFormatter.StripFormat(m_AboutText));
				finalString.AppendLine();
			}

			if (m_AboutTextLong != null)
			{
				finalString.AppendLine(ConsoleFormatter.StripFormat(m_AboutTextLong));
				finalString.AppendLine();                
			}

			finalString.AppendLine();
			finalString.AppendLine();
			finalString.AppendLine(new string('=', RC.BufferWidth));
			finalString.AppendLine();

			finalString.AppendLine(ConsoleFormatter.StripFormat(string.Format("{0}:", Strings.ArgumentParser_AboutScreen_Usage)));

			if (m_UsageText != null)
			{                
				finalString.AppendLine(ConsoleFormatter.StripFormat(m_UsageText));
				finalString.AppendLine();
				finalString.AppendLine();
			}

			finalString.AppendLine(GetLongArgumentsUsage());            
			finalString.AppendLine();

			if (m_FirstArgument != null)
			{
				if (Helper.IsNotNullOrEmpty(m_FirstArgument.Help))
				{
					finalString.AppendLine(new string('-', RC.BufferWidth));
					finalString.AppendLine(("<" + m_FirstArgument.ArgumentString().Trim() + ">"));
					finalString.AppendLine(ConsoleFormatter.StripFormat(m_FirstArgument.Help));
					finalString.AppendLine();
				}
			}

			if (m_DefaultArgument != null)
			{
				if (Helper.IsNotNullOrEmpty(m_DefaultArgument.Help))
				{
					finalString.AppendLine(new string('-', RC.BufferWidth));
					finalString.AppendLine(("<" + m_DefaultArgument.ArgumentString().Trim() + ">"));
					finalString.AppendLine(ConsoleFormatter.StripFormat(m_DefaultArgument.Help));
					finalString.AppendLine();
				}
			}

			foreach (ArgumentKey k in m_Switches.Keys)
			{
				finalString.AppendLine(new string('-', RC.BufferWidth));
				finalString.Append(GetIndividualHelpString(k));
				//finalString.AppendLine();
			}

			if (m_LegalText != null)
			{
				finalString.AppendLine();
				finalString.AppendLine();
				finalString.AppendLine(new string('=', RC.BufferWidth));
				finalString.AppendLine(ConsoleFormatter.StripFormat(m_LegalText));
				finalString.AppendLine();
			}

			try
			{
				File.WriteAllText(path, finalString.ToString());
				RC.Write(ConsoleVerbosity.Normal, ConsoleThemeColor.Text1, string.Format(Strings.ArgumentParser_DocumentationWrittenToPath, path));
			}
			catch (Exception ex)
			{
				RC.WriteException(0010, string.Format(Strings.Error_0010,path), ex); 
			}
		}

		#endregion        

		#endregion 
	}	
}
